/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import org.aswing.ASWingUtils;
import org.aswing.border.EmptyBorder;
import org.aswing.BorderLayout;
import org.aswing.Box;
import org.aswing.Container;
import org.aswing.GeneralListCellFactory;
import org.aswing.geom.Dimension;
import org.aswing.geom.Point;
import org.aswing.Icon;
import org.aswing.Insets;
import org.aswing.JButton;
import org.aswing.JComboBox;
import org.aswing.JFrame;
import org.aswing.JLabel;
import org.aswing.JList;
import org.aswing.JListTree;
import org.aswing.JPanel;
import org.aswing.JScrollPane;
import org.aswing.JTextField;
import org.aswing.ListCell;
import org.aswing.SoftBox;
import org.aswing.SoftBoxLayout;
import org.aswing.tree.DefaultMutableTreeNode;
import org.aswing.tree.DefaultTreeModel;
import org.aswing.VectorListModel;

import com.bourre.commands.Delegate;
import com.bourre.events.DynBasicEvent;

import fever.app.context.browser.HTTPFilesystem;
import fever.app.local.LocalisationEvent;
import fever.app.menu.FvContextMenuEvent;
import fever.app.menu.FvContextMenuItem;
import fever.data.libs.BitmapLibLocator;
import fever.display.ModalScreen;
import fever.Fever;
import fever.log.FeverDebug;
import fever.utils.Stringifier;
import fever.utils.StringUtil;

import fvaswing.app.context.browser.FvFileDialogItem;
import fvaswing.app.context.browser.FvFileDialogListCell;
import fvaswing.app.context.browser.FvFileDialogTreeCell;
import fvaswing.cells.FvContextMenuCellEvent;
import fvaswing.cells.FvListCellFactory;
import fvaswing.components.FvBitmapIcon;
import fvaswing.components.FvInputComponentDialog;
import fvaswing.components.FvLabelButton;
import fvaswing.components.input.FvTextFieldInput;

/**
 * @author Romain Ecarnot
 */
class fvaswing.app.context.browser.FvFileDialogView
{
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private static var _instance : FvFileDialogView;
	
	private var _frame : JFrame;
	private var _modal : ModalScreen;
	
	private var _lookInLabel : JLabel;
	private var _lookInCombo : JComboBox;
	
	private var _parentButton : FvLabelButton;
	private var _newFolderButton : FvLabelButton;
	private var _newFolderButton2 : JButton;
	
	private var _fileList : JList;
	
	private var _folderListModel : DefaultTreeModel;	private var _folderRootNode : DefaultMutableTreeNode;
	private var _folderList : JListTree;
	
	private var _filenameLabel : JLabel;
	private var _filenameInput : JTextField;
	private var _filetypeLabel : JLabel;
	private var _filetypeCombo : JComboBox;
	
	private var _approuveFileButton : JButton;
	private var _cancelFileButton : JButton;
	
	private var _approuveFolderButton : JButton;
	private var _cancelFolderButton : JButton;
	
	private var _fileContainer : Container;
	private var _folderContainer : Container;
	
	private var _minimumWidth : Number;
	
	private var _handler : Delegate;
	private var _filesystem : HTTPFilesystem;
	private var _selections : Array;
	
	private var _deleteItem : FvContextMenuItem;	private var _renameItem : FvContextMenuItem;
	
	
	//-------------------------------------------------------------------------
	// Public Properties
	//-------------------------------------------------------------------------
	
	/** 
	 * Icon ID for folder tree node in 'Browse Folder' view.
	 * 
	 * <p>If not defined, use default 
	 * {@link fvaswing.app.context.browser.FvTreeFolderIcon} icon representation.
	 */
	public static var folderIcon : String;
	
	/** 
	 * Icon ID for file list item in 'File Open / Save' view.
	 * 
	 * <p>If not defined, use default 
	 * {@link fvaswing.app.context.browser.FvListFileIcon} icon representation.
	 */	public static var fileIcon : String;
	
	/** 
	 * Icon ID for 'go to parent folder' button.
	 */
	public static var parentIcon : String;
	
	/** 
	 * Icon ID for 'create folder' button.
	 */
	public static var createIcon : String;
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Returns ( and / or creates ) {@link FvBrowserFileView} instance.
	 * 
	 * //TODO Local / HTTP Interface
	 */
	public static function getInstance( ) : FvFileDialogView
	{
		if( !_instance ) _instance = new FvFileDialogView( HTTPFilesystem.getInstance() );
		return _instance;	
	}
	
	/**
	 * Constructor.
	 * 
	 * //TODO Local / HTTP Interface
	 */
	public function FvFileDialogView( filesystem  )
	{
		_minimumWidth = 75;
		_filesystem = filesystem;
		_selections = new Array();
		
		_configureUI();
	}
	
	/**
	 * Opens 'File save' dialog.
	 */
	public function showFileOpenDialog( event : DynBasicEvent ) : Void
	{
		_filenameInput.setEditable( false );
		_fileList.setSelectionMode( ( event.multipleSelect == true ) ? JList.MULTIPLE_SELECTION : JList.SINGLE_SELECTION );
		_updateFileModel( _lookInCombo.getSelectedItem().toString() );
		
		_parseGlobalEvent( event );
		
		_openDialog( _fileContainer );
	}
	
	/**
	 * Opens 'File save' dialog.
	 */
	public function showFileSaveDialog( event : DynBasicEvent ) : Void
	{
		_filenameInput.setEditable( true );
		_fileList.setSelectionMode( JList.SINGLE_SELECTION );
		_updateFileModel( _lookInCombo.getSelectedItem().toString() );
		
		_parseGlobalEvent( event );
		
		_openDialog( _fileContainer );
	}
	
	/**
	 * Opens 'Browse folder' dialog.
	 */
	public function showBrowseFolderDialog( event : DynBasicEvent ) : Void
	{
		_parseGlobalEvent( event );
		
		_openDialog( _folderContainer );
		_folderListModel.reload( _folderRootNode );
	}
	
	public function onLocalisationUpdate( event : LocalisationEvent ) : Void
	{
		_lookInLabel.setText( 'Look in' );
		
		_parentButton.setToolTipText( 'Parent folder' );
		_newFolderButton.setToolTipText( 'Create a new folder' );
				_newFolderButton2.setText( 'Create a new folder' );		
		_filenameLabel.setText( 'Filename' );
		_filetypeLabel.setText( 'File type' );
		
		_approuveFileButton.setText( 'open' );
		_cancelFileButton.setText( 'cancel' );
		
		_approuveFolderButton.setText( 'ok' );
		_cancelFolderButton.setText( 'cancel' );
	}
	
	/**
	 * Returns string representation.
	 */
	public function toString() : String
	{
		return Stringifier.parse( this );
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private function _openDialog( targetContainer : Container ) : Void
	{
		_updateFolderModel();
		
		_frame.setContentPane( targetContainer );
		
		_centerFrame();
		
		_modal.show();
		_frame.show();
	}
	
	private function _parseGlobalEvent( event : DynBasicEvent ) : Void
	{
		_frame.setTitle( event.caption );
		_handler = event.callback;	
	}
	
	private function _configureUI() : Void
	{
		 _fileContainer = _createBasicPanel();
		 _fileContainer.append( _buildFileHeader(), BorderLayout.NORTH );
		 _fileContainer.append( _buildFileList(), BorderLayout.CENTER );		 _fileContainer.append( _buildFileFooter(), BorderLayout.SOUTH );
		 
		 _folderContainer = _createBasicPanel();
		 _folderContainer.append( _buildFolderList(), BorderLayout.CENTER );
		 _folderContainer.append( _buildFolderFooter(), BorderLayout.SOUTH );
		 
		 _buildFrame();
		 
		 onLocalisationUpdate();
	}
	
	private function _getModalTarget() : MovieClip
	{
		_modal.dispose();
		_modal = new ModalScreen( 0x000000, 0 );
				
		return _modal.getModalTarget();
	}
	
	private function _buildFrame() : Void
	{
		_frame = new JFrame( _getModalTarget(), '', false );
		_frame.setResizable( true );
		_frame.setClosable( true );
		_frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
		_frame.setSize( new Dimension( 400, 300 ) );
		_frame.addEventListener( JFrame.ON_WINDOW_CLOSING, _onFrameClose, this );
	}
	
	private function _buildFileHeader() : Container
	{
		_lookInLabel = _createFixLabel( '-' );
		_lookInCombo = new JComboBox();
		_lookInCombo.addActionListener( _onGoFolderChange, this );
		
		var pIcon : Icon;
		if( BitmapLibLocator.getLocator().isRegistredBitmap( FvFileDialogView.parentIcon ) )
			pIcon = FvBitmapIcon.create( FvFileDialogView.parentIcon );	
		
		if( pIcon ) _parentButton = new FvLabelButton( pIcon );
		else _parentButton = new FvLabelButton( 'P' );
		_parentButton.setUseHandCursor( false );
		_parentButton.addActionListener( _onGoParentClick, this );
		
		var cIcon : Icon;
		if( BitmapLibLocator.getLocator().isRegistredBitmap( FvFileDialogView.createIcon ) )
			cIcon = FvBitmapIcon.create( FvFileDialogView.createIcon );	
		
		if( cIcon ) _newFolderButton = new FvLabelButton( cIcon );
		else _newFolderButton = new FvLabelButton( 'N' );
		_newFolderButton.setUseHandCursor( false );
		_newFolderButton.addActionListener( _onCreateFolderClick, this );
		
		var bBox : SoftBox = new SoftBox( SoftBoxLayout.X_AXIS, 5, SoftBoxLayout.RIGHT );
		bBox.append( _parentButton );
		bBox.append( _newFolderButton );
		
		var pane : JPanel = new JPanel( new BorderLayout( 5, 5 ) );
		pane.append( _lookInLabel, BorderLayout.WEST );		pane.append( _lookInCombo, BorderLayout.CENTER );		pane.append( bBox, BorderLayout.EAST );
		
		return pane;
	}
	
	private function _buildFileList() : Container
	{
		_deleteItem = new FvContextMenuItem( 'delete' );
 	   	_renameItem = new FvContextMenuItem( 'rename' );
 		
		_fileList = new JList();
		_fileList = new JList( null, new FvListCellFactory( new FvFileDialogListCell(), 30, [ _deleteItem, _renameItem ] ) );
		
		_fileList.addEventListener( JList.ON_ITEM_CLICKED, _onItemListClick, this );		_fileList.addEventListener( FvContextMenuCellEvent.onContextCellItemEVENT, _onItemContextClick, this );		
		var scroll : JScrollPane = new JScrollPane( _fileList );
		scroll.setOpaque( true );
		return scroll;
	}
	
	private function _buildFileFooter() : Container
	{
		_filenameLabel = _createFixLabel( '-' );	
		_filenameInput = new JTextField();
		
		_approuveFileButton = _createChoiceButton( '-' );
		_approuveFileButton.addActionListener( _onApprouveFile, this );
		
		_filetypeLabel = _createFixLabel( '-' );	
		_filetypeCombo = new JComboBox();
		_cancelFileButton = _createChoiceButton( '-' );		_cancelFileButton.addActionListener( _onFrameClose, this );
		
		var nameLine : JPanel = new JPanel( new BorderLayout( 5, 5 ) );
		nameLine.append( _filenameLabel, BorderLayout.WEST ); 		nameLine.append( _filenameInput, BorderLayout.CENTER ); 		nameLine.append( _approuveFileButton, BorderLayout.EAST ); 
		
		var typeLine : JPanel = new JPanel( new BorderLayout( 5, 5 ) );
		typeLine.append( _filetypeLabel, BorderLayout.WEST ); 
		typeLine.append( _filetypeCombo, BorderLayout.CENTER ); 
		typeLine.append( _cancelFileButton, BorderLayout.EAST );
		
		var pane : SoftBox = new SoftBox( SoftBoxLayout.Y_AXIS, 5 );
		pane.append( nameLine );
		pane.append( typeLine );
		
		return pane;
	}
	
	private function _buildFolderList() : Container
	{
		_folderRootNode = new DefaultMutableTreeNode( 'filesystem' );
		_folderListModel = new DefaultTreeModel( _folderRootNode );
		_folderList = new JListTree( _folderListModel, new GeneralListCellFactory( FvFileDialogTreeCell, false, true) );
		
		var scroll: JScrollPane = new JScrollPane( _folderList );
		scroll.setOpaque( true );
		
		return scroll;
	}
	
	private function _updateFolderModel() : Void
	{
		_folderRootNode.removeAllChildren();
		
		var a : Array = new Array();
		a.push( _nodePathToString( _folderRootNode.getPath() ) );
		
		_fileSystemToTreeModel( _folderRootNode, _filesystem.getContent(), a );
		
		a.sort();
		_lookInCombo.setListData( a );
		
		if( _lookInCombo.getSelectedIndex() < 0 ) _lookInCombo.setSelectedIndex( 0 );
	}
	
	private function _fileSystemToTreeModel( parent : DefaultMutableTreeNode, content : Object, a : Array ) : Void
	{
		for( var s : String in content )
		{
			if( typeof( content[s] ) == 'object' )
			{
				var node : DefaultMutableTreeNode = new DefaultMutableTreeNode( s ); 
				parent.append( node );
				a.push( _nodePathToString( node.getPath() ) ) ;
				
				_fileSystemToTreeModel( node, content[s], a );	
			}
		}
	}
	
	private function _nodePathToString( a : Array ) : String
	{
		var s : String = a.join( '/' ) + '/';
		return StringUtil.replace( s, 'filesystem', '' );
	}
	
	private function _updateFileModel( folder : String ) : Void
	{
		var content : Object = _filesystem.getContent( folder );
		var v : VectorListModel = new VectorListModel();
		
		for( var s : String in content ) 
		{
			var item : FvFileDialogItem;
			
			if( typeof( content[s] ) == 'object' )
				item = new FvFileDialogItem( s, true );
			else
				item = new FvFileDialogItem( s, false );
			
			v.append( item );
		}
		
		v.sortOn( [ 'type', 'name' ], Array.CASEINSENSITIVE );
		
		_fileList.setModel( v );
		_selections = new Array();
		_fileList.setSelectedIndices( [] );
		
		_filenameInput.setText();
	}
	
	
	private function _updateCurrentModel() : Void
	{
		_updateFolderModel();
		_lookInCombo.fireActionEvent();
	}
	
	private function _buildFolderFooter() : Container
	{
		_approuveFolderButton = _createChoiceButton( '-' );		_approuveFolderButton.addActionListener( _onApprouveFolder, this );
		
		_cancelFolderButton = _createChoiceButton( '-' );
		_cancelFolderButton.addActionListener( _onFrameClose, this );
		
		_newFolderButton2 = new JButton( '-' );
		_newFolderButton2.addActionListener( _onCreateFolderClick2, this );
		
		var line : SoftBox = new SoftBox( SoftBoxLayout.X_AXIS, 5 );
		line.append( _approuveFolderButton );
		line.append( _cancelFolderButton );
		
		var p : JPanel = new JPanel( new BorderLayout( 5, 5 ) );
		p.append( _newFolderButton2, BorderLayout.WEST );
		p.append( Box.createHorizontalBox( 5 ), BorderLayout.CENTER );
		p.append( line, BorderLayout.EAST );
		
		return p;
	}
	
	private function _createBasicPanel() : JPanel
	{
		var p : JPanel = new JPanel( new BorderLayout( 5, 5 ) );
		p.setBorder( new EmptyBorder( null, new Insets( 5,5,5,5 ) ) );
		
		return p;
	}
	
	private function _createFixLabel( caption : String ) : JLabel
	{
		var label : JLabel = new JLabel( caption, JLabel.LEFT );
		label.setPreferredWidth( _minimumWidth );
		
		return label;	
	}
	
	private function _createChoiceButton( caption : String ) : JButton
	{
		var b : JButton = new JButton( caption );
		b.setPreferredWidth( _minimumWidth );
		
		return b;
	}
	
	private function _centerFrame() : Void
	{
		var location : Point = ASWingUtils.getScreenCenterPosition();
		location.x -= _frame.getWidth()/2;
		location.y -= _frame.getHeight()/2;
		_frame.setLocation( location );
	}
	
	private function _closeFrame() : Void
	{
		_modal.hide();
		_frame.tryToClose();
	}
	
	private function _onItemListClick( source : JListTree, value : FvFileDialogItem, cell : ListCell, clickCount : Number ) : Void
	{
		if( clickCount == 2 )
		{
			if( value.isDirectory() )
			{
				_lookInCombo.setSelectedItem( _lookInCombo.getSelectedItem().toString() + value.name + '/' );
			}
			else _onApprouveFile();
		}
		else
		{
			_renameItem.enabled = ( _fileList.getSelectedIndices().length < 2 );			_deleteItem.enabled = ( _fileList.getSelectedIndices().length < 2 );
			
			if( value.isDirectory() ) return;
			
			if( !_filenameInput.isEditable() ) // open mode
			{
				_selections = _fileList.getSelectedValues();
				_filenameInput.setText( _selections.join(';') );	
			}	
			else
			{
				_filenameInput.setText( value.name );
			}
		}
	}
	
	private function _onItemContextClick( source : JListTree, event : FvContextMenuEvent ) : Void
	{
		var a : Array = _fileList.getSelectedValues().concat();
		var l : Number = a.length;
		var item : FvContextMenuItem = event.getItem();
		var current : String = _lookInCombo.getSelectedItem().toString();
		var folder : String = StringUtil.leftTrim( current, '/' );
		
		for ( var i : Number = 0; i < l; i++ ) 
		{
			var value : FvFileDialogItem = 	a[i];
			if( value.isDirectory() )
			{
				switch( true )
				{
					case ( item == _renameItem ) :
						_callRenameFolder( folder + value.name + '/' );
						break;
					case ( item == _deleteItem ) :
						_callDeleteFolder( folder, value.name );
						break;
				}
			}
			else
			{
				switch( true )
				{
					case ( item == _renameItem ) :
						_callRenameFile( folder + value.name );
						break;
					case ( item == _deleteItem ) :
						_callDeleteFile( folder, value.name );
						break;
				}	
			}
		}
	}
	
	private function _callRenameFile( filepath : String ) : Void
	{
		var input : FvTextFieldInput = new FvTextFieldInput();
		input.setRestrict( 'a-z A-Z 0-9._\\-' );
		
		var dialog : FvInputComponentDialog = new FvInputComponentDialog( input );
		dialog.open( 'new filename', this, _onNewFileName, filepath );
	}
	
	private function _onNewFileName( result : String, filepath : String ) : Void
	{
		if( result )
		{
			var b : Boolean = _filesystem.renameFile( filepath, result );
			if( b ) _updateCurrentModel();
			else FeverDebug.ERROR( 'rename file error' );	
		}	
	}
	
	private function _callRenameFolder( folderpath : String ) : Void
	{
		var input : FvTextFieldInput = new FvTextFieldInput();
		input.setRestrict( 'a-z A-Z 0-9_\\-' );
		
		var dialog : FvInputComponentDialog = new FvInputComponentDialog( input );
		dialog.open( 'new filename', this, _onNewFolderName, folderpath );
	}
	
	private function _onNewFolderName( result : String, folderpath : String ) : Void
	{
		if( result )
		{
			var b : Boolean = _filesystem.renameDirectory( folderpath, result );
			if( b ) _updateCurrentModel();
			else FeverDebug.ERROR( 'rename folder error' );
		}	
	}
	
	private function _callDeleteFile( folder : String, filename : String ) : Void
	{
		Fever.dialog.confirm( 'Are you sure you want to remove \'' + filename + '\' file ?', new Delegate( this, _onConfirmFileDeletion, folder, filename ) );
	}
	
	private function _onConfirmFileDeletion( folder : String, filename : String, result : Boolean ) : Void
	{
		if( result )
		{
			var b : Boolean = Fever.io.deleteFile( folder + filename );
			if( b ) _updateCurrentModel();
		}
	}
	
	private function _callDeleteFolder( folder : String, foldername : String ) : Void
	{
		Fever.dialog.confirm( 'Are you sure you want to remove \'' + foldername + '\' directory ?', new Delegate( this, _onConfirmFolderDeletion, folder, foldername ) );
	}
	
	private function _onConfirmFolderDeletion( folder : String, foldername : String, result : Boolean ) : Void
	{
		if( result )
		{
			var b : Boolean = Fever.io.deleteDirectory( folder + foldername + '/' );
			if( b ) _updateCurrentModel();
			else FeverDebug.ERROR( 'delete directory error' );
		}
	}
	
	private function _onApprouveFile( source : JButton ) : Void
	{
		var args : String;
		
		var folder : String = _lookInCombo.getSelectedItem().toString();
		folder = StringUtil.leftTrim( folder, '/' );
			
		if( !_filenameInput.isEditable() ) // open mode
		{
			if( _fileList.getSelectedIndices().length > 0 )
			{
				var l : Number = _selections.length;
				var a : Array = new Array();
				
				for (var i : Number = 0; i < l; i++) 
				{
					a.push( folder + _selections[ i ] );
				}
				args = a.join( ';' );
			}
			else args = null;
		}
		else
		{
			var target : String = StringUtil.trim( _filenameInput.getText() );
			if( target ) args = folder + target;
			else return;
		}
		
		_closeFrame();
		
		_handler.setArguments( args );
		_handler.execute();
	}
	
	private function _onApprouveFolder( source : JButton ) : Void
	{
		if( _folderList.getSelectionPath() != null )
		{
			var a : Array = _folderList.getSelectionPath().getPath().slice( 1 );
			_handler.setArguments( a.join( '/' ) + '/' );
		}
		else _handler.setArguments( null );
		
		_closeFrame();
		
		_handler.execute();
	}
	
	private function _onFrameClose( source : JFrame ) : Void
	{
		_closeFrame();
		
		_handler.setArguments( null );
		_handler.execute();
	}
	
	private function _onGoFolderChange( source : JComboBox ) : Void
	{
		_updateFileModel( source.getSelectedItem().toString() );	
	}
	
	private function _onGoParentClick( source : JButton ) : Void
	{
		if( _lookInCombo.getSelectedIndex() > 0 )
		{
			var current : String = _lookInCombo.getSelectedItem().toString();
			current = StringUtil.rightTrim( current, '/' );
			
			var n : String = current.substring( 0, current.lastIndexOf( '/' ) + 1 );
			_lookInCombo.setSelectedItem( n );
		}
	}
	
	private function _onCreateFolderClick( source : JButton ) : Void
	{
		var input : FvTextFieldInput = new FvTextFieldInput();
		input.setRestrict( 'a-z A-Z 0-9_-' );
		
		var dialog : FvInputComponentDialog = new FvInputComponentDialog( input );
		dialog.open( 'new directory name', this, _onInputFolder );
	}
	
	private function _onInputFolder( result : String ) : Void
	{
		if( result )
		{
			var current : String = _lookInCombo.getSelectedItem().toString();
			var newFolder : String = _lookInCombo.getSelectedItem().toString() + result + '/';
			 
			var b : Boolean = _filesystem.createDirectory( newFolder );
			if( b )
			{
				_updateFolderModel();
				_lookInCombo.fireActionEvent();
			}
			else FeverDebug.ERROR( 'folder creation error' );
		}
	}
	
	private function _onCreateFolderClick2( source : JButton ) : Void
	{
		
	}
}